home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Macintosh Common Lisp Related / User Contributions / dm Folder.sea / dm Folder / dm-use.lisp < prev    next >
Encoding:
Text File  |  1993-02-12  |  19.2 KB  |  438 lines  |  [TEXT/CCL2]

  1. ;;; ================================================================
  2. ;;;
  3. ;;;                The Dungeon Master
  4. ;;;
  5. ;;;               An alternative module system
  6. ;;;
  7. ;;;                Version 1.0
  8. ;;;
  9. ;;;              Recommendations for use
  10. ;;;
  11. ;;; ================================================================
  12.  
  13. ;;; Copyright (c) 1993 Massachusetts Institute of Technology.
  14. ;;; Permission is granted to use this documentation and to pass on copies,
  15. ;;; provided that this copyright notice is retained intact.  In addition,
  16. ;;; permission is granted to modify this documentation, provided all
  17. ;;; changes are prominently marked.  For more details, refer to the
  18. ;;; accompanying file "dm-copyright.text".
  19.  
  20. ;;; Brought to you by the Laboratory for Advanced Technology in the
  21. ;;; Humantities (formerly the Athena Language Learning Project) at MIT.
  22. ;;; "Bigger!  Better!  Slower!"
  23.  
  24. ;;; Software by Sue Felshin and Stuart Malone.  Documentation by Sue
  25. ;;; Felshin.
  26.  
  27. ;;; The Dungeon Master system consists of six files:
  28. ;;;   1) source code ("dungeon-master.lisp"),
  29. ;;;   2) a detailed copyright notice ("copyright.text"),
  30. ;;;   3) user documentation in mss (Scribe) format ("dm.mss"),
  31. ;;;   4) PostScript format ("dm.text"), and
  32. ;;;   5) text format, and
  33. ;;;   6) a description of how to use the Dungeon Master ("dm-use.lisp").
  34. ;;; This is file number 6.
  35.  
  36. ;;; If you improve the Dungeon Master, you are encouraged to mail changes
  37. ;;; to sfelshin@athena.mit.edu.
  38.  
  39. ;;; This file recommends how to use the Dungeon Master by giving an example
  40. ;;; of integrating it into a lisp project.
  41.  
  42.  
  43. ;;; ================================================================
  44. ;;;
  45. ;;;                  Recommended Use
  46. ;;;
  47. ;;; ================================================================
  48.  
  49. ;;; You will need three files, in addition to the various modules of your
  50. ;;; system.  This document describes these three files, with appropriate
  51. ;;; example code, then gives an example of a typical module, and finally
  52. ;;; contains a few general comments on using the Dungeon Master.
  53.  
  54.  
  55. ;;; ================================================================
  56. ;;; First file: the Dungeon Master.
  57.  
  58. ;;; If you use a configuration other than Lucid on the RS/6000 or MCL, you
  59. ;;; must configure the Dungeon Master for your configuration.  Search for
  60. ;;; calls to CONFIGURE-ME-ERROR in the Dungeon Master file.  Add the
  61. ;;; appropriate code for your lisp.  In some cases this will consist merely
  62. ;;; of adding your lisp's distinguishing feature(s) to an existing #+ form
  63. ;;; and subtracting them from the associated #-'ed configure-me-error form.
  64. ;;; In other cases, you will have to add a small amount of code.  After you
  65. ;;; have configured your lisp, please send your changes to
  66. ;;; sfelshin@athena.mit.edu so that they can be integrated into the
  67. ;;; official cody of the Dungeon Master.
  68.  
  69.  
  70. ;;; ================================================================
  71. ;;; Second file: set up packages.
  72.  
  73. ;;; Because of the way the package system is defined (or not defined) in
  74. ;;; CLtL2, it is impossible to reliably define packages in a distributed
  75. ;;; manner, such that they can also be modified on the fly.  Set up a
  76. ;;; single file for your project which defines _all_ packages, all at once.
  77.  
  78. ;;; In point of fact, you need only define mutually dependent packages
  79. ;;; simultaneously.  Therefore, you could have multiple package sets, one
  80. ;;; for each set of mutually dependent packages.  However, every time you
  81. ;;; modify a package in a package set, you must reload not only the
  82. ;;; modified package set, but also all package sets which depend on that
  83. ;;; set.  You will probably find it most convenient to define as many
  84. ;;; packages as possible in the same set, even if they are not all mutually
  85. ;;; dependent.
  86. ;;;
  87. ;;; The MIT LATH NLP project, for example, is a general NLP system which
  88. ;;; can be used with a variety of control modules.  Our project takes the
  89. ;;; tack of defining one package set file for the entire NLP system, plus
  90. ;;; one package set file for each control module.  Each control module
  91. ;;; package set is dependent on the NLP package set, but the NLP package
  92. ;;; set is independent of the control modules.
  93.  
  94. ;;; This example of DEFINE-PACKAGES is an abbreviated version of the code
  95. ;;; used by the MIT LATH NLP system.
  96. ;;;
  97. ;;; The :NAME, :NICKNAMES, :SHADOW, :SHADOWING-IMPORT, :EXPORT, :USE, and
  98. ;;; :IMPORT keywords related to the package system as described by CLtL2.
  99. ;;;
  100. ;;; The :GLOBAL keyword allows symbols to be made "global" (accessible
  101. ;;; without package prefix from every package defined by DEFINE-PACKAGES)
  102. ;;; by importing them into exporting them from the DM package, which is
  103. ;;; used by all packages defined by DEFINE-PACKAGES.  It is tasteless to
  104. ;;; make symbols which are used non-interactively global.
  105. ;;;
  106. ;;; Not all Common Lisps are 100% CLtL2 compatible yet.  Lisps which do not
  107. ;;; contain a built-in pretty printer and/or condition system must use the
  108. ;;; public domain implementations of these systems.  If the
  109. ;;; :PRETTY-PRINTING or :CONDITIONS keyword is given a true value for a
  110. ;;; package, DEFINE-PACKAGES will ensure that the specified system(s)
  111. ;;; is/are present and that their code is available to the package.
  112. ;;;
  113. ;;; All keywords take lists of symbol names as their values with the
  114. ;;; exception of the :SHADOWING-IMPORT and :IMPORT keywords.  In place of
  115. ;;; each symbol name, these take a list of a symbol name and the name of
  116. ;;; the package from which to import the symbol.
  117.  
  118. (define-packages
  119.  
  120.   ;; ================================================================
  121.   ;; Independent packages (packages which depend on no other packages, but
  122.   ;; which are used by later packages in this form).
  123.  
  124.   ((:name "PROBES")
  125.    (:export
  126.     "PROBING-P" "UNLESS-PROBING" "UNPROBE-QUIETLY" "DEFINE-PROBE"
  127.     "PROBE-QUIETLY" "ENSURE-THAT" "WHEN-PROBING")
  128.    ;; Debugging stuff, to be called interactively.  These symbols don't
  129.    ;; have to be explicitly exported, because making them global takes care
  130.    ;; of that.
  131.    (:global "PROBE" "UNPROBE" "PROBES")
  132.    ;; This is an independent package, so it doesn't use anything (except
  133.    ;; the *base-packages*, which DEFINE-PACKAGES will automatically make
  134.    ;; all packages use).
  135.    (:use))
  136.  
  137.   ((:name "BACKTRACE")
  138.    (:export "BACKTRACE-STRING")
  139.    #+lucid
  140.    #.`(:import ,@(mapcar #'(lambda (name) (list name "LUCID"))
  141.              '("*DEBUGGER-FRAMES*" "COLLECT-STACK-FRAMES"
  142.                "NEWEST-UNHIDDEN-STACK-FRAME-INDEX"
  143.                "PREVIOUS-UNHIDDEN-STACK-FRAME-INDEX"
  144.                "STACK-FRAME-NAME" "STACK-FRAME-SOURCE-CODE"
  145.                "STACK-FRAME-LENGTH" "STACK-FRAME-LOCAL-NAME"
  146.                "STACK-FRAME-LOCAL-VALUE" "AVOID-STACK-FRAME-P")))
  147.    (:use))
  148.  
  149.   ;; ================================================================
  150.   ;; Non-mutually dependent packages (packages which depend only on
  151.   ;; independent packages defined higher in this form).
  152.  
  153.   ;; Typical simple package.  Export some symbols and then use some
  154.   ;; packages defined in the previous section of this form.
  155.   ((:name "ITER")
  156.    (:export
  157.     "DEFITER" "ITERATE" "YIELD")
  158.    (:use "PROBES"))
  159.  
  160.   ((:name "RESOURCES")
  161.    ;; Lucid 4.0.0 hasn't implemented the COMMON-LISP package yet, and
  162.    ;; exports all kinds of non-Common-Lisp standard symbols from its
  163.    ;; LUCID-COMMON-LISP package.
  164.    #+lucid (:shadow "MAKE-RESOURCE")
  165.    (:export "DEFRESOURCE" "ALLOCATE" "RESET-RESOURCE" "DEALLOCATE")
  166.    (:use "PROBES"))
  167.  
  168.   ((:name "REGISTRAR")
  169.    (:export
  170.     "MAKE-REGISTRY" "REGISTER" "REGISTRY" "DO-REGISTRY"
  171.     "WRITE-REGISTRY-INITIALIZATION" "WRITE-REGISTRY-FINALIZATION"
  172.     "WRITE-REGISTRIES" "WRITE-REFERENCE"
  173.     "*REGISTRY-VECTOR*" "REGISTRAR-READ-MACRO")
  174.    (:use "PROBES")
  175.    ;; The registrar makes use of the pretty printer.
  176.    (:pretty-printing t))
  177.  
  178.   ((:name "TRANSLITERATE")
  179.    (:export
  180.     "TSTRING-DOWNCASE" "TOKEN-NAME" "KEYBOARD-INPUT" "INTERN-TOKEN"
  181.     "UNKNOWN-TOKEN"
  182.     "TOKEN-EQUAL" "TOKEN-LOWER-CASE-P" "TOKEN-STRING" "TSTRING-CAPITALIZE"
  183.     "*STANDARD-SYMBOL-CHARACTER-SET*" "TOKEN-ALPHABETIC-P" "DEFINE-TOKEN"
  184.     "READ-TOKEN-NO-HANG" "LEXICON-EXTERNAL" "TOKEN" "PARSE-TOKEN" "WRITE-TOKEN"
  185.     "LEXICON-INTERNAL" "*STANDARD-CHARACTER-SET*" "READ-TOKEN"
  186.     "TOKEN-UPPER-CASE-P" "TSTRING-EQUAL" "TSTRING-UPCASE" "TSTRING-CAPITULATE"
  187.     "TOKEN-WHITESPACE-P" "TOKEN-PUNCTUATION-P" "TRANSLITERATE-STRING"
  188.     "DEFINE-CHARACTER-SET" "BRACKET-MACRO")
  189.    (:use "ITER" "PROBES")
  190.    ;; The transliterater makes use of the condition system.
  191.    (:conditions t))
  192.  
  193.   ;; ================================================================
  194.   ;; Mutually dependent packages (packages which use each other).
  195.  
  196.   ((:name "HISTORIAN")
  197.    (:nicknames "HIST")
  198.    (:export
  199.     "BEGIN-CHAPTER" "SAVE-HISTORY" "ADD-TO-CHAPTER" "RESET-HISTORIAN"
  200.     "PRINT-HISTORY" "END-CHAPTER" "EMPTY-CHAPTER")
  201.    (:use "INPUT" "TRANSLITERATE"))
  202.  
  203.   ((:name "INPUT")
  204.    ;; See note at package RESOURCES.  Under Lucid, *prompt* is used in
  205.    ;; controlling the lisp prompt.
  206.    #+lucid (:shadow "*PROMPT*")
  207.    (:shadowing-import
  208.     ;; Our extension to CLOS.  I forget which lisp defines its own
  209.     ;; definstance, so that we must shadow it.
  210.     ("DEFINSTANCE" "ALLP"))
  211.    (:export
  212.     ;; From module :input-conditions.
  213.     "RESET-UNKNOWN-WORD-LIST" "*UNKNOWN-WORD-LIST*" "USE-NIL"
  214.     "*X-INPUT-STREAM*"
  215.     "FATAL-UNKNOWN-WORD-TOKENS" "UNKNOWN-WORD" "UNKNOWN-WORD-TOKENS"
  216.     "UNKNOWN-WORD-SURFACE-STRING" "USE-GENERIC-WORDS"
  217.     "FATAL-UNKNOWN-WORD" "FATAL-UNKNOWN-WORD-SURFACE-STRING"
  218.  
  219.     ;; From module :input.
  220.     "*IO-WINDOW-P*" "REPARSE"
  221.     "PROMPT-INPUT-EDITOR-FOR-LINE" "*X-INPUT-EDITOR*" "*IO-WINDOW-STREAM*"
  222.     "CLOSE-INPUT-EDITOR" "END-OF-INPUT-STRING" "*END-OF-INPUT-READ-TIME*"
  223.     "CLOSE-IO-WINDOW" "TOKENS-TO-STRING" "OPEN-IO-WINDOW"
  224.     "END-OF-INPUT" "ACCEPT-INPUT" "INPUT-PROMISE" "RESTART-INPUT-EDITOR"
  225.     "INITIAL-INPUT-PROMISE" "OPEN-INPUT-EDITOR" "RESTART-IO-WINDOW")
  226.    (:global "OPEN-IO-WINDOW" "CLOSE-IO-WINDOW" "RESTART-IO-WINDOW")
  227.    (:use "PROBES" "BACKTRACE" "TRANSLITERATE" "HISTORIAN"))
  228.  
  229.   )
  230.  
  231.  
  232. ;;; ================================================================
  233. ;;; Third file: a loader file.
  234.  
  235. ;;; The simplest way to load a system is to define a single file which
  236.  
  237. ;;;    1) Loads the Dungeon Master.  The Dungeon Master is a file, not a
  238. ;;;      module, so use LOAD.
  239.  
  240. (load (make-pathname
  241.        :name "dungeon-master"
  242.        :type nil
  243.        :defaults *load-pathname*))
  244.  
  245. ;;;    2) Sets up the search path.  E.g., to push the directory of the
  246. ;;;      loader file:
  247.  
  248. (push-module-search-path *load-pathname*)
  249.  
  250. ;;;    3) Loads any necessary package sets.  One could define package sets
  251. ;;;      in modules, rather than files, but this is not recommended.
  252.  
  253. (load (make-pathname
  254.        :name "all-pkgs"
  255.        :type nil
  256.        :defaults *load-pathname*))
  257.  
  258. ;;;    4) Loads the toplevel module of the system using REQUIRE-MODULE.  If
  259. ;;;      the module is named "toplevel-code", then:
  260.  
  261. (dm:require-module :toplevel-code)
  262.  
  263.  
  264. ;;; ================================
  265.  
  266. ;;; As a slightly more complex example, I'll describe what the MIT LATH NLP
  267. ;;; loader file does.  In this system, there are multiple control modules,
  268. ;;; any one of which can be loaded on top of the general NLP system.  This
  269. ;;; loader file
  270. ;;;    1) Loads patches for the lisp configuration.
  271. ;;;    2) Loads the Dungeon Master.  (It also loads a few other extensions
  272. ;;;      to Common Lisp).
  273. ;;;    3) Sets up a basic search path.  It pushes half a dozen directories
  274. ;;;      in which language independent code is stored onto the search
  275. ;;;      path.  Then it queries the user for a language to use and pushes
  276. ;;;      a subdirectory for that language onto the search path.  Each
  277. ;;;      language's subdirectory contains the same set of modules, so that
  278. ;;;      the appropriate language's module is loaded by virtue of its
  279. ;;;      directory being present on the search path.  (Multiple languages
  280. ;;;      can't be loaded simultaneously.
  281. ;;;    4) Loads the basic NLP package set.
  282. ;;;    5) Queries the user for a control module to load.  Pushes a the
  283. ;;;      control module's subdirectory onto the search path.  Chooses a
  284. ;;;      toplevel module to load based on the control module.
  285. ;;;    6) Loads the toplevel module of the chosen control module using
  286. ;;;      REQUIRE-MODULE.
  287.  
  288.  
  289. ;;; ================================================================
  290. ;;; Fourth file: a typical module.
  291.  
  292. ;;; In an ideal world, package information could be distributed as well as
  293. ;;; the requiring of modules.  We at the MIT LATH typically put package
  294. ;;; information in modules, commented out.  We pretend that the package
  295. ;;; system is distributed, because it's easier to maintain that way.  Using
  296. ;;; this method, any time a package definition is changed, one must change
  297. ;;; both the official package set file and the comments in the relevant
  298. ;;; module.
  299.  
  300. ;;; <<PARENTHETICAL FLAME ON>>
  301. ;;;
  302. ;;; Without completely rewriting the package system, it is impossible to
  303. ;;; distribute package information across files, since one file in a
  304. ;;; package might cause symbols to be interned locally in the package (say,
  305. ;;; by using them as local variables) which coincidentally later turn out
  306. ;;; to be imported from another package by another file in the same
  307. ;;; package.  However, it should be possible to distribute packages in
  308. ;;; separate file.  Every module would have to contain a call to
  309. ;;; REQUIRE-PACKAGE at the top, which would ensure that a package-defining
  310. ;;; module is loaded.  (Ideally this call would replace the call to
  311. ;;; IN-PACKAGE.)  All information for the package would have to be present
  312. ;;; in the package-defining module, rather than being distributed across
  313. ;;; modules.  Still, packages would only be loaded as necessary, rather
  314. ;;; than possibly unnecessary packages being loaded by the single package
  315. ;;; set file.
  316. ;;;
  317. ;;; To be friendly, one might provide a new set of functions, parallel to
  318. ;;; USE-PACKAGE, SHADOW, IMPORT, etc., which would be used within modules.
  319. ;;; These functions would signal errors if the package system was found to
  320. ;;; be inconsistent with the information specified by the arguments to the
  321. ;;; new functions.  This would provide the appearance of a distributed
  322. ;;; package system, for development purposes.
  323. ;;;
  324. ;;; In such a system, it would be an error if any inconsistencies were
  325. ;;; found in the package system in a production system, but in a
  326. ;;; development system, package inconsistencies would always result in
  327. ;;; errors with reasonable restarts (this latter is already the case in
  328. ;;; many lisp implementations).  But be that as it may...
  329. ;;;
  330. ;;; <<PARENTHETICAL FLAME OFF>>
  331.  
  332. ;;; Remember GLS's Put In Seven Extremely Random User Interface Commands?
  333. ;;; It still holds, mostly, except that the in-package command must come
  334. ;;; first, because PROVIDE-MODULE isn't built in to Common Lisp.
  335.  
  336. ;;; "In": This package is created in the package set file.
  337. (in-package :typical)
  338.  
  339. ;;; "Put": There are N modules in this subsystem.  This one is named
  340. ;;; :typical-1.  The file name is identical to the module name, except that
  341. ;;; it may be upper, lower, or mixed case, and may be truncated, according
  342. ;;; to the limits and abilities of the file system.
  343. (provide-module :typical-1
  344.   ;; I don't know why, but every time I compile this module in Crufty Lisp,
  345.   ;; I get bogus code.
  346.   #+crufty-lisp :compile #+crufty-lisp nil)
  347.  
  348.  
  349. ;;; "Seven": Shadow symbols if desired.  (Not these symbols, I hope!)
  350. #||(shadow '(cons car cdr))||#
  351.  
  352. ;;; "Extremely"
  353. #||(export '(make-typical-struct typical-struct-slot do-typical-stuff))||#
  354.  
  355. ;;; "Random User": Do these in pairs, because it's easier to read that way.
  356. ;;; Using packages was taken care of by the package set file, anyway.
  357. ;;; Also, making use of the condition system and pretty printer is
  358. ;;; essentially equivalent to requiring them.
  359.  
  360. #||(use-condition-system)||#
  361.  
  362. ;;; We make use of a macro from the :iter module.  Say so, so that the DM
  363. ;;; can arrange to reload and/or compile this module if module :iter
  364. ;;; changes.
  365. (require-module :iter :macros t)
  366. #||(use-package :iter)||#
  367.  
  368. ;;; Don't have to use a package because module :typical-support is in
  369. ;;; package :typical.  Module :typical-support defines macros and structs
  370. ;;; which this module makes use of.
  371. (require-module :typical-support
  372.   :macros t :constructors t :accessors t :modifiers t)
  373.  
  374. (require-module :typical-data
  375.   ;; These days I'm trying out some experimental new data, but I didn't
  376.   ;; want to touch the old data.
  377.   :path "new-typical-data")
  378.  
  379. ;;; "Interface"
  380. ;;; This is the only symbol we want from this package, so we'll import it
  381. ;;; rather than using the package.
  382. #||(import '(transliterate:transliterate-string))||#
  383.  
  384. ;;; "Commands": the contents of the module.
  385.  
  386.  
  387. ;;; ================================================================
  388. ;;; General comments.
  389.  
  390. ;;; The MIT LATH has found the Dungeon Master to be convenient and easy to
  391. ;;; use, but, due to the size of the system (half a dozen or more
  392. ;;; subdirectories, around a score of packages, and well over a hundred
  393. ;;; modules), a few quirks and problems have reared their ugly heads.
  394.  
  395. ;;; 1) When two modules are mutually dependent in such a way that in order
  396. ;;; to compile each, the other must be compiled, the Dungeon Master will
  397. ;;; first compile one, then compile the other, and then recompile the
  398. ;;; first.  This looks strange, but is appropriate behavior.
  399.  
  400. ;;; 2) It is possible to cause an infinite loop in loading.  When one
  401. ;;; module depends on another such that the second must be loaded before
  402. ;;; the first can be loaded (typically because the first module loads data
  403. ;;; using code defined in the second module), the DM must completely load
  404. ;;; the second module before loading the first.  If the second module
  405. ;;; requires the first module, or requires other modules which eventually
  406. ;;; require the first module, the DM may get into an infinite loop of
  407. ;;; nested loading of the two modules in question (and possibly
  408. ;;; intermediate modules).  The only solution is to reorganize one's code
  409. ;;; to eliminate loading loops.
  410. ;;;
  411. ;;; Keep in mind that there are valid situations where the DM may start to
  412. ;;; load one module, then another, and then the first again, but where at
  413. ;;; this point the first module will be successfully loaded (after which
  414. ;;; the second module will load, and then the first will be redundantly
  415. ;;; loaded again).  Whether a loop becomes infinite or terminates at the
  416. ;;; second iteration depends on the lisp configuration and the keywords
  417. ;;; passed to the relevant calls to REQUIRE-MODULE.
  418.  
  419. ;;; 3) Some, if not all, configurations have a limit on the number of file
  420. ;;; streams that can be open at one time.  In a very large system, it may
  421. ;;; be necessary to rearrange your code to avoid exceeding this limit.
  422. ;;; Usually, simply rearranging the order of calls to REQUIRE-MODULE in
  423. ;;; various modules is sufficient to reduce the loading depth.  If you
  424. ;;; require generic tool modules first (which rarely load other modules),
  425. ;;; then local support modules, then other major substem, you are not
  426. ;;; likely to run into this problem.
  427.  
  428. ;;; 4) You must be careful to name your modules such that no two module
  429. ;;; names are identical for the legal file name length on your
  430. ;;; architecture, as the DM will truncate module names to the legal file
  431. ;;; name length.  This being the modern world, one is not likely to
  432. ;;; encounter this problem, thank goodness.  However, as recently as five
  433. ;;; years ago, IBM RTs running AIX had a file name length of a mere 14
  434. ;;; characters.  Subtracting one for a dot, one for an extension, and one
  435. ;;; for a twiddle (~) for Emacs's sake, this left a usable file name length
  436. ;;; of eleven characters, and the MIT LATH ran up against this in one
  437. ;;; instance!
  438.